package com.lemon.cloud.admin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.anno.CreateCache;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.lemon.cloud.admin.dto.OrgDTO;
import com.lemon.cloud.admin.entity.UserOrg;
import com.lemon.cloud.admin.mapper.SysOrgMapper;
import com.lemon.cloud.admin.service.SysOrgService;
import com.lemon.cloud.admin.service.UserOrgService;
import com.lemon.cloud.comm.constants.CacheConstants;
import com.lemon.cloud.comm.constants.enums.DelFlagEnum;
import com.lemon.cloud.comm.po.SysOrg;
import com.lemon.cloud.security.util.SecurityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static com.lemon.cloud.comm.constants.CommonConstants.ORG_TREE_ROOT_ID;

@Service
public class SysOrgServiceImpl extends ServiceImpl<SysOrgMapper, SysOrg> implements SysOrgService {

    @Autowired
    private UserOrgService userOrgService;

    @CreateCache(name = CacheConstants.SYS_ORG_DESCENDANT)
    private Cache<String,List<SysOrg>> descendantCache;

    @Override
    public List<SysOrg> selectByUserId(Long userId) {
        return baseMapper.selectByUserId(userId);
    }

    @Override
    public List<Tree<Long>> getOrgTree() {
        List<SysOrg> list = baseMapper.getDataScopeOrg();
        return getDeptTree(list, ORG_TREE_ROOT_ID);
    }

    private List<Tree<Long>> getDeptTree(List<SysOrg> list, Long parentId) {
        if (CollectionUtil.isEmpty(list) || ObjectUtil.isNull(parentId)) {
            return Lists.newArrayList();
        }
        List<TreeNode<Long>> collect = list.stream().filter(dept -> dept.getId().intValue() != dept.getParentId())
                .sorted(Comparator.comparingInt(SysOrg::getSortOrder)).map(dept -> {
                    TreeNode<Long> treeNode = new TreeNode<>();
                    treeNode.setId(dept.getId());
                    treeNode.setParentId(dept.getParentId());
                    treeNode.setName(dept.getName());
                    treeNode.setWeight(dept.getSortOrder());
                    // 扩展属性
                    Map<String, Object> extra = new HashMap<>(4);
                    extra.put("createTime", dept.getCreateTime());
                    treeNode.setExtra(extra);
                    return treeNode;
                }).collect(Collectors.toList());

        return TreeUtil.build(collect, parentId);
    }

    /**
     * 新增部门
     *
     * @param orgDTO
     * @return
     */
    @Override
    public SysOrg addOrg(OrgDTO orgDTO) {
        SysOrg org = new SysOrg();
        BeanUtils.copyProperties(orgDTO, org);
        //查询同级部门是否有重复名称部门
        validOrg(org);
        baseMapper.addOrg(org);
        return org;
    }

    private void validOrg(SysOrg org) {
        Long commName = baseMapper.selectCount(new LambdaQueryWrapper<SysOrg>()
                .eq(SysOrg::getParentId, org.getParentId())
                .eq(SysOrg::getDelFlag, DelFlagEnum.EXIST.getValue())
                .ne(org.getId() != null, SysOrg::getId, org.getId())
                .eq(SysOrg::getName, org.getName())
        );
        Assert.state(commName == 0, "同级部门有重复名称部门");

        if (!ORG_TREE_ROOT_ID.equals(org.getParentId())) {
            SysOrg parentOrg = baseMapper.selectOne(new LambdaQueryWrapper<SysOrg>()
                    .eq(SysOrg::getId, org.getParentId())
                    .eq(SysOrg::getDelFlag, DelFlagEnum.EXIST.getValue())
                    .select(SysOrg::getId, SysOrg::getName, SysOrg::getParentId, SysOrg::getParentIds, SysOrg::getSortOrder)
            );
            Assert.state(parentOrg != null, "父级部门不存在");
            org.setParentIds(parentOrg.getParentIds() + StrUtil.COMMA + parentOrg.getId());
        } else {
            org.setParentIds(ORG_TREE_ROOT_ID.toString());
        }
        if (org.getId() == null) {
            org.setCreateTime(LocalDateTime.now());
            org.setCreateBy(SecurityUtils.getUser().getUsername());
        }
        org.setUpdateTime(LocalDateTime.now());
        org.setUpdateBy(SecurityUtils.getUser().getUsername());
    }

    @Override
    public SysOrg getOrg(Long id) {
        return baseMapper.selectOne(new LambdaQueryWrapper<SysOrg>()
                .eq(SysOrg::getId, id)
                .eq(SysOrg::getDelFlag, DelFlagEnum.EXIST.getValue())
                .select(SysOrg::getId, SysOrg::getName, SysOrg::getParentId, SysOrg::getParentIds, SysOrg::getSortOrder)
        );
    }

    @Override
    public SysOrg updateOrg(OrgDTO orgDTO) {
        SysOrg org = new SysOrg();
        BeanUtils.copyProperties(orgDTO, org);

        //查询同级部门是否有重复名称部门
        validOrg(org);
        //查询当前部门
        SysOrg exist = baseMapper.selectOne(new LambdaQueryWrapper<SysOrg>()
                .eq(SysOrg::getId, orgDTO.getId())
                .eq(SysOrg::getDelFlag, DelFlagEnum.EXIST.getValue())
                .select(SysOrg::getId, SysOrg::getName, SysOrg::getParentId, SysOrg::getParentIds, SysOrg::getSortOrder)
        );
        Assert.state(exist != null, "部门不存在");

        //判断子部门
        String parentIds = exist.getParentIds() + StrUtil.COMMA + org.getId();
        descendantCache.removeAll(Sets.newHashSet(parentIds.split(StrUtil.COMMA)));
        this.update(new LambdaUpdateWrapper<SysOrg>()
                .eq(SysOrg::getId, org.getId())
                .set(SysOrg::getName, org.getName())
                .set(SysOrg::getParentId, org.getParentId())
                .set(SysOrg::getParentIds, org.getParentIds())
                .set(SysOrg::getSortOrder, org.getSortOrder())
                .set(SysOrg::getUpdateBy, org.getUpdateBy())
                .set(SysOrg::getUpdateTime, org.getUpdateTime())
        );
        return org;
    }

    @Override
    public Boolean delOrg(Long id) {
        long count = userOrgService.count(new LambdaQueryWrapper<UserOrg>().eq(UserOrg::getOrgId, id));
        Assert.state(count == 0, "无法删除，存在用户关联该部门");

        //查询当前部门
        SysOrg org = baseMapper.selectOne(new LambdaQueryWrapper<SysOrg>()
                .eq(SysOrg::getId, id)
                .eq(SysOrg::getDelFlag, DelFlagEnum.EXIST.getValue())
                .select(SysOrg::getId, SysOrg::getName, SysOrg::getParentId, SysOrg::getParentIds, SysOrg::getSortOrder)
        );
        Assert.state(org != null, "部门不存在");

        //判断子部门
        String parentIds = org.getParentIds() + StrUtil.COMMA + org.getId();
        descendantCache.removeAll(Sets.newHashSet(parentIds.split(StrUtil.COMMA)));
        List<SysOrg> childOrgList = baseMapper.selectList(new LambdaQueryWrapper<SysOrg>()
                .likeRight(SysOrg::getParentIds, parentIds)
                .eq(SysOrg::getDelFlag, DelFlagEnum.EXIST.getValue())
                .select(SysOrg::getId, SysOrg::getName, SysOrg::getParentId, SysOrg::getParentIds, SysOrg::getSortOrder)
        );
        List<Long> childIdSet = Lists.newArrayList();
        if (CollectionUtil.isNotEmpty(childOrgList)) {
            childIdSet.addAll(childOrgList.stream().map(SysOrg::getId).collect(Collectors.toList()));
            List<UserOrg> userOrgList = userOrgService.list(new LambdaQueryWrapper<UserOrg>().in(UserOrg::getOrgId, childIdSet));
            if (CollectionUtil.isNotEmpty(userOrgList)) {
                childIdSet.clear();
                childIdSet.addAll(userOrgList.stream().map(UserOrg::getOrgId).collect(Collectors.toList()));
                String relationUserOrg = StrUtil.join(StrUtil.COMMA, childOrgList.stream().filter(item -> childIdSet.contains(item.getId())).collect(Collectors.toSet())
                        .stream().map(SysOrg::getName).collect(Collectors.toSet()));

                Assert.state(CollectionUtil.isEmpty(userOrgList), "“" + relationUserOrg + "”,存在用户关联这些部门");
            }
        }
        childIdSet.add(id);
        this.update(new LambdaUpdateWrapper<SysOrg>()
                .in(SysOrg::getId, childIdSet)
                .set(SysOrg::getUpdateBy, SecurityUtils.getUser().getUsername())
                .set(SysOrg::getUpdateTime, LocalDateTime.now())
                .set(SysOrg::getDelFlag, DelFlagEnum.DELETE.getValue())
        );
        return Boolean.TRUE;
    }

    /**
     * 查询本部及子部门
     * @param orgIds
     * @return
     */
    @Override
    public List<SysOrg> getDescendantList(List<String> orgIds) {
        if (CollectionUtil.isEmpty(orgIds)){
            return Lists.newArrayList();
        }
        //查询当前部门

        List<SysOrg> childOrgList = Lists.newArrayList();
        orgIds.forEach(item->{
            childOrgList.addAll(descendantCache.computeIfAbsent(item,(i)-> getDescendantById(item)));
        });
        return childOrgList;
    }


    public List<SysOrg> getDescendantById(String orgId){
        SysOrg sysOrg = baseMapper.selectOne(new LambdaQueryWrapper<SysOrg>()
                .eq(SysOrg::getId, orgId)
                .eq(SysOrg::getDelFlag, DelFlagEnum.EXIST.getValue())
                .select(SysOrg::getId, SysOrg::getName, SysOrg::getParentId, SysOrg::getParentIds, SysOrg::getSortOrder)
        );
        if (sysOrg==null){
            return Lists.newArrayList();
        }
        LambdaQueryWrapper<SysOrg> lambda = new LambdaQueryWrapper<SysOrg>()
                .eq(SysOrg::getDelFlag, DelFlagEnum.EXIST.getValue())
                .select(SysOrg::getId, SysOrg::getName, SysOrg::getParentId)
                .and(buildChildLambda(Collections.singletonList(sysOrg)));
        //判断子部门

        List<SysOrg> childOrgList = baseMapper.selectList(lambda);
        childOrgList.add(sysOrg);
        return childOrgList;
    }


    private Consumer<LambdaQueryWrapper<SysOrg>> buildChildLambda(List<SysOrg> sysOrgs){
        return (cl)->{
            for (SysOrg org : sysOrgs){
                String parentIds = org.getParentIds() + StrUtil.COMMA + org.getId();
                cl.or().likeRight(SysOrg::getParentIds,parentIds);
            }
        };
    }
}

